﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Runtime.Serialization;
using System.Configuration;
using System.Web.SessionState;
using System.Web;
using SmartParking.Data.Entities;

namespace SmartParking.Bussiness
{
    public static class PayPalManager
    {
        public static PayPalModel PostToPayPal(HttpApplicationState application, HttpRequestBase request, HttpSessionStateBase session, string email, string ipAddress)
        {
            var url =
                request.Url.OriginalString.Substring(0, request.Url.OriginalString.LastIndexOf(request.Url.Authority)) +
                request.Url.Authority;
            var userId = SecurityManager.GetUser(email).UserID;
            var paypal = new PayPalModel()
                {
                    Command = "_cart",
                    ActionUrl = PayPalSettings.ActionUrl,
                    Business = PayPalSettings.Business,
                    NoShipping = PayPalSettings.NoShipping,
                    CurrencyCode = PayPalSettings.CurrencyCode,
                    PaymentUrl = String.Format("{0}{1}", url, PayPalSettings.PaymentUrl),
                    NotifyUrl = String.Format("{0}{1}", url, PayPalSettings.NotifyUrl),
                    ReturnUrl = String.Format("{0}{1}/{2}", url, PayPalSettings.ReturnUrl, session.SessionID),
                    CancelUrl = String.Format("{0}{1}/{2}", url, PayPalSettings.CancelUrl, session.SessionID),
                    Invoice = session.SessionID,
                    Custom = String.Format("{0};{1}", userId.ToString(), ipAddress) // UserId;IPAddress
                };

            var reservations = ReservationsManager.GetLiveReservations(application, session);
            reservations.ForEach(item => paypal.PayPalItems.Add(CopyReservationData(reservations.IndexOf(item) + 1, item)));

            ReservationsManager.ProcessLiveReservations(application, session);

            return paypal;
        }

        private static PayPalItemModel CopyReservationData(int number, OrderDetail reservation)
        {
            var item = new PayPalItemModel
                {
                    Number = number.ToString(),
                    Name =
                        String.Format("{0} {1} {2} {3} {4} Placa: {5}",
                                      ParkingManager.GetParking(reservation.ParkingID).Name.Trim(),
                                      ParkingManager.GetParkingZone(reservation.ParkingZoneID).Name.Trim(),
                                      reservation.ReservationStartDateTime.Value.ToString("dd/MM/yyyy"),
                                      reservation.ReservationStartDateTime.Value.ToString("hh:mm tt"),
                                      reservation.ReservationEndDateTime.Value.ToString("hh:mm tt"),
                                      reservation.CarPlate.Trim()),
                    Amount = ((reservation.Amount + reservation.Commission)/SmartParkingSettings.TipoCambio).ToString(),
                    Quantity = "1",
                    Tax = "0"
                };
            return item;
        }

        public struct PayPalResponse
        {
            public PayPalResponseStatus Status;
            public NameValueCollection Info;
        }

        public enum PayPalResponseStatus
        {
            Verified,
            Invalid,
            Unknown
        }

        private static PayPalResponse ToPayPalResponse(string response, NameValueCollection info)
        {
            var result = new PayPalResponse() { Info = info };
            switch (response)
            {
                case "VERIFIED":
                    result.Status = PayPalResponseStatus.Verified;
                    break;
                case "INVALID":
                    result.Status = PayPalResponseStatus.Invalid;
                    break;
                default:
                    result.Status = PayPalResponseStatus.Unknown;
                    break;
            }
            return result;
        }

        /// <summary>
        /// Utility method for handling PayPal IPN Responses
        /// </summary>
        public static PayPalResponse GetPayPalIPNResponse(HttpRequestBase request, bool useSandbox)
        {
            var formVals = new Dictionary<string, string>();
            formVals.Add("cmd", "_notify-validate");
            return GetPayPalResponse(request, formVals, useSandbox);
        }

        /// <summary>
        /// Utility method for handling PayPal Responses
        /// </summary>
        private static PayPalResponse GetPayPalResponse(HttpRequestBase request, Dictionary<string, string> formVals, bool useSandbox)
        {
            //var paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/cgi-bin/webscr" : "https://www.paypal.com/cgi-bin/webscr";
            var paypalUrl = PayPalSettings.ActionUrl;
            var req = WebRequest.Create(paypalUrl) as HttpWebRequest;

            // Set values for the request back
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";

            var param = request.BinaryRead(request.ContentLength);
            var strRequest = Encoding.ASCII.GetString(param);
            //LogManager.Info(1, "127.0.0.1", String.Format("[DEBUG: GetPayPalResponse] Request: {0}", strRequest));
            var responseInfo = HttpUtility.ParseQueryString(strRequest); //Save a copy of the initial info sent by PayPal

            var sb = new StringBuilder();
            sb.Append(strRequest);
            foreach (var key in formVals.Keys)
            {
                sb.AppendFormat("&{0}={1}", key, formVals[key]);
            }
            strRequest += sb.ToString();
            req.ContentLength = strRequest.Length;

            //for proxy
            //WebProxy proxy = new WebProxy(new Uri("http://urlort#");
            //req.Proxy = proxy;
            //Send the request to PayPal and get the response
            var response = "";
            using (var streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII))
            {
                streamOut.Write(strRequest);
                streamOut.Close();
                using (var streamIn = new StreamReader(req.GetResponse().GetResponseStream()))
                {
                    response = streamIn.ReadToEnd();
                }
            }
            //LogManager.Info(1, "127.0.0.1", String.Format("[DEBUG: GetPayPalResponse] Response: {0}", response));
            return ToPayPalResponse(response, responseInfo);
        }

        public static bool AmountPaidIsValid(Order order, decimal amountPaid)
        {
            //pull the order
            bool result = true;

            if (order != null)
            {
                if (order.TotalAmount != amountPaid)
                {
                    //_logger.Warn("Invalid order amount to PDT/IPN: " + order.ID + "; Actual: " + amountPaid.ToString("C") + "; Should be: " + order.Total.ToString("C") + "user IP is " + Request.UserHostAddress);
                    result = false;
                }
            }
            else
            {
                //_logger.Warn("Invalid order ID passed to PDT/IPN; user IP is " + Request.UserHostAddress);
            }
            return result;
        }
    }

    public class PayPalModel
    {
        public PayPalModel()
        {
            PayPalItems = new List<PayPalItemModel>();
        }

        public string Command { get; set; }
        public string ActionUrl { get; set; }
        public string Business { get; set; }
        public string NoShipping { get; set; }
        public string CurrencyCode { get; set; }
        public string PaymentUrl { get; set; }
        public string NotifyUrl { get; set; }
        public string ReturnUrl { get; set; }
        public string CancelUrl { get; set; }
        public string Language { get; set; }
        public string Invoice { get; set; }
        public string Custom { get; set; }
        public List<PayPalItemModel> PayPalItems { get; set; }
    }

    public class PayPalItemModel
    {
        public string Number { get; set; }
        public string Name { get; set; }
        public string Quantity { get; set; }
        public string Amount { get; set; }
        public string Tax { get; set; }
    }

    public static class PayPalSettings
    {
        public static bool Sandbox
        {
            get
            {
                return AppSettings.Setting<bool>("PayPal:Sandbox");
            }
        }

        public static string Business
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:Business");
            }
        }

        public static string NoShipping
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:NoShipping");
            }
        }

        public static string CurrencyCode
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:CurrencyCode");
            }
        }

        public static string Language
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:Language");
            }
        }

        public static bool UseApi
        {
            get
            {
                return AppSettings.Setting<bool>("PayPal:UseApi");
            }
        }

        public static string ApiDomain
        {
            get
            {
                return Sandbox ? "api-3t.sandbox.paypal.com" : "api-3t.paypal.com";
            }
        }

        public static string CgiDomain
        {
            get
            {
                return Sandbox ? "www.sandbox.paypal.com" : "www.paypal.com";
            }
        }

        public static string Signature
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:Signature");
            }
        }

        public static string Username
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:Username");
            }
        }

        public static string Password
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:Password");
            }
        }

        public static string ActionUrl
        {
            get
            {
                return String.Format("https://{0}/{1}/cgi-bin/webscr", UseApi ? ApiDomain : CgiDomain, Language);
            }
        }

        public static string PaymentUrl
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:PaymentUrl");
            }
        }

        public static string NotifyUrl
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:NotifyUrl");
            }
        }

        public static string ReturnUrl
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:ReturnUrl");
            }
        }

        public static string CancelUrl
        {
            get
            {
                return AppSettings.Setting<string>("PayPal:CancelUrl");
            }
        }

        public static string PayPalPayNowButtonUrl
        {
            get
            {
                return String.Format(AppSettings.Setting<string>("PayPal:PayPalPayNowButtonUrl"), Language);
            }
        }
    }
}
